package com.zhang.search.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zhang.common.model.SkuEsModel;
import com.zhang.common.dto.SkuSearchDto;
import com.zhang.common.model.SkuRecommendModel;
import com.zhang.search.config.ElasticsearchConfig;
import com.zhang.search.service.IProductElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class IProductElasticSearchServiceImpl implements IProductElasticSearchService {

    public final String PRODUCT_INDEX = "product";//sku数据在ES中的索引
    @Autowired
    RestHighLevelClient client;

    @Override
    public void productUp(List<SkuEsModel> skuEsModels) throws IOException {
        /*1、建立索引*/
        /*2保存数据*/
        BulkRequest bulkRequest = new BulkRequest();
        for (SkuEsModel skuEsModel : skuEsModels) {
//            指定索引
            IndexRequest indexRequest = new IndexRequest(PRODUCT_INDEX);
//            指定文档id
            indexRequest.id(skuEsModel.getSkuId().toString());
//            指定内容
            String jsonStr = JSON.toJSONString(skuEsModel);
            indexRequest.source(jsonStr, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        BulkResponse bulk = client.bulk(bulkRequest, ElasticsearchConfig.COMMON_OPTIONS);
        /*判断是否有误*/
        boolean b = bulk.hasFailures();//true:有错误，false没有错误
        List<String> collect = Arrays.stream(bulk.getItems()).map(BulkItemResponse::getId).collect(Collectors.toList());
        if (b) {
            log.error("商品上架错误:{}", collect);
            throw new RuntimeException("商品上架失败");
        }
    }

    @Override
    public List<SkuEsModel> getSkuFromES(SkuSearchDto skuSearchDto) throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices(PRODUCT_INDEX);
        // 指定检索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        /**
         * 从es中查询，先模拟查询语句
         */
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//使用组合查询
        if (!StrUtil.isBlank(skuSearchDto.getSearchValue())) {
            /*可选---should*/
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle", skuSearchDto.getSearchValue()));
//            如果页面传入的是分类名称也应该可以搜索出来
            boolQueryBuilder.should(QueryBuilders.matchQuery("categoryName", skuSearchDto.getSearchValue()));
//        高亮显示
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("skuTitle");//那个字段匹配高亮
            highlightBuilder.preTags("<span style='color:red'>");//前缀
            highlightBuilder.postTags("</span>");//后缀
            builder.highlighter(highlightBuilder);
        }
        if (!StrUtil.isBlank(skuSearchDto.getBusinessId())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("businessId", skuSearchDto.getBusinessId()));
        }
        if (skuSearchDto.getBrandIds() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("brandId", skuSearchDto.getBrandIds()));
        }
//        分类
        if (skuSearchDto.getCategoryIds() != null) {
            for (Long categoryId : skuSearchDto.getCategoryIds()) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("categoryId", categoryId));
//                boolQueryBuilder.should(QueryBuilders.termQuery("categoryId", categoryId));
            }
        }
//        价格区间
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
        if (skuSearchDto.getMinPrice() != 0) {
            rangeQuery.gte(skuSearchDto.getMinPrice());
        }
        if (skuSearchDto.getMaxPrice() != 0) {
            rangeQuery.lte(skuSearchDto.getMaxPrice());
        }
        boolQueryBuilder.filter(rangeQuery);
//        排序
        switch (skuSearchDto.getSortManner()) {
            case "0":
                if ("1".equals(skuSearchDto.getSortState())) {
                    builder.sort("skuPrice", SortOrder.DESC);
                } else {
                    builder.sort("skuPrice", SortOrder.ASC);
                }
                break;
            case "1":
                if ("1".equals(skuSearchDto.getSortState())) {
                    builder.sort("upTime", SortOrder.DESC);
                } else {
                    builder.sort("upTime", SortOrder.ASC);
                }
                break;
            default:
                break;
        }
//        分页
        int currentPage = skuSearchDto.getPageNum();
        int pageSize = skuSearchDto.getPageSize();
        int from = (currentPage - 1) * pageSize;
        builder.from(from);
        builder.size(pageSize);
        builder.query(boolQueryBuilder);
        request.source(builder);
        // 3、发送请求到ES
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4、处理响应结果
        return Arrays.stream(response.getHits().getHits()).map(item -> JSON.parseObject(item.getSourceAsString(), SkuEsModel.class)).collect(Collectors.toList());
    }

    @Override
    public List<SkuEsModel> getSkuListByAdvice(SkuRecommendModel skuRecommendModel) throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices(PRODUCT_INDEX);
        // 指定检索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        /**
         * 从es中查询，先模拟查询语句
         */
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//使用组合查询
        if (skuRecommendModel != null) {
            if (skuRecommendModel.getSearchWord() != null) {
                /*可选---should*/
                for (String s : skuRecommendModel.getSearchWord()) {
                    boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle", s));
                }
            }
            if (skuRecommendModel.getBrandIds() != null) {
                for (Long brandId : skuRecommendModel.getBrandIds()) {
                    boolQueryBuilder.should(QueryBuilders.termQuery("brandId", brandId));
                }
            }
            //        分类
            if (skuRecommendModel.getCategoryIds() != null) {
                for (Long categoryId : skuRecommendModel.getCategoryIds()) {
                    boolQueryBuilder.should(QueryBuilders.termQuery("categoryId", categoryId));
                }
            }
        } else {
//            TODO 游客应当推荐其他的查询方式：如：评分，最新上架等等
        }
//        只查询20条记录，懒得管前端提交的分页数据了
        builder.from(0);
        builder.size(20);
        builder.query(boolQueryBuilder);
        request.source(builder);
        // 3、发送请求到ES
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4、处理响应结果
        return Arrays.stream(response.getHits().getHits()).map(item -> JSON.parseObject(item.getSourceAsString(), SkuEsModel.class)).collect(Collectors.toList());
    }

    @Override
    public void updateSkuSaleCount(String skuId, Integer quantity) throws IOException {
        UpdateRequest updateRequest = new UpdateRequest(PRODUCT_INDEX, skuId);
        updateRequest.doc("saleCount", quantity);
        client.update(updateRequest, RequestOptions.DEFAULT);
    }
}
